Trò chơi Tic-Tac-Toe, game đánh caro full source code
- PhotonEditor.cs
- PhotonNetwork /
- Editor /
- Photon Unity Networking /
- Assets /
- project /
2 // <copyright file="PhotonEditor.cs" company="Exit Games GmbH">
3 // PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH
4 // </copyright>
5 // <summary>
6 // MenuItems and in-Editor scripts for PhotonNetwork.
7 // </summary>
8 // <author>developer@exitgames.com</author>
9 // ----------------------------------------------------------------------------
10 using System;
11 using System.Collections.Generic;
12 using System.IO;
13 using System.Reflection;
14 using ExitGames.Client.Photon;
15 using UnityEditor;
16 using UnityEditorInternal;
17 using UnityEngine;
18
19
20 public class Text
21 {
22 public string WindowTitle = "PUN Wizard";
23 public string SetupWizardWarningTitle = "Warning";
24 public string SetupWizardWarningMessage = "You have not yet run the Photon setup wizard! Your game won't be able to connect. See Windows -> Photon Unity Networking.";
25 public string MainMenuButton = "Main Menu";
26 public string ConnectButton = "Connect to Photon Cloud";
27 public string UsePhotonLabel = "Using the Photon Cloud is free for development. If you don't have an account yet, enter your email and register.";
28 public string SendButton = "Send";
29 public string EmailLabel = "Email:";
30 public string SignedUpAlreadyLabel = "I am already signed up. Let me enter my AppId.";
31 public string SetupButton = "Setup";
32 public string RegisterByWebsiteLabel = "I want to register by a website.";
33 public string AccountWebsiteButton = "Open account website";
34 public string SelfHostLabel = "I want to host my own server. Let me set it up.";
35 public string SelfHostSettingsButton = "Open self-hosting settings";
36 public string MobileExportNoteLabel = "Build for mobiles impossible. Get PUN+ or Unity Pro for mobile.";
37 public string MobilePunPlusExportNoteLabel = "PUN+ available. Using native sockets for iOS/Android.";
38 public string EmailInUseLabel = "The provided e-mail-address has already been registered.";
39 public string KnownAppIdLabel = "Ah, I know my Application ID. Get me to setup.";
40 public string SeeMyAccountLabel = "Mh, see my account page";
41 public string SelfHostSettingButton = "Open self-hosting settings";
42 public string OopsLabel = "Oops!";
43 public string SeeMyAccountPage = "";
44 public string CancelButton = "Cancel";
45 public string PhotonCloudConnect = "Connect to Photon Cloud";
46 public string SetupOwnHostLabel = "Setup own Photon Host";
47 public string PUNWizardLabel = "Photon Unity Networking (PUN) Wizard";
48 public string SettingsButton = "Settings";
49 public string SetupServerCloudLabel = "Setup wizard for setting up your own server or the cloud.";
50 public string WarningPhotonDisconnect = "";
51 public string ConverterLabel = "Converter";
52 public string StartButton = "Start";
53 public string UNtoPUNLabel = "Converts pure Unity Networking to Photon Unity Networking.";
54 public string SettingsFileLabel = "Settings File";
55 public string LocateSettingsButton = "Locate settings asset";
56 public string SettingsHighlightLabel = "Highlights the used photon settings file in the project.";
57 public string DocumentationLabel = "Documentation";
58 public string OpenPDFText = "Open PDF";
59 public string OpenPDFTooltip = "Opens the local documentation pdf.";
60 public string OpenDevNetText = "Open DevNet";
61 public string OpenDevNetTooltip = "Online documentation for Photon.";
62 public string OpenCloudDashboardText = "Open Cloud Dashboard";
63 public string OpenCloudDashboardTooltip = "Review Cloud App information and statistics.";
64 public string OpenForumText = "Open Forum";
65 public string OpenForumTooltip = "Online support for Photon.";
66 public string QuestionsLabel = "Questions? Need help or want to give us feedback? You are most welcome!";
67 public string SeeForumButton = "See the Photon Forum";
68 public string OpenDashboardButton = "Open Dashboard (web)";
69 public string AppIdLabel = "Your AppId";
70 public string AppIdInfoLabel = "The AppId a Guid that identifies your game in the Photon Cloud. Find it on your dashboard page.";
71 public string CloudRegionLabel = "Cloud Region";
72 public string RegionalServersInfo = "Photon Cloud has regional servers. Picking one near your customers improves ping times. You could use more than one but this setup does not support it.";
73 public string SaveButton = "Save";
74 public string SettingsSavedTitle = "Success";
75 public string SettingsSavedMessage = "Saved your settings.\nConnectUsingSettings() will use the settings file.";
76 public string OkButton = "Ok";
77 public string SeeMyAccountPageButton = "Mh, see my account page";
78 public string SetupOwnServerLabel = "Running my app in the cloud was fun but...\nLet me setup my own Photon server.";
79 public string OwnHostCloudCompareLabel = "I am not quite sure how 'my own host' compares to 'cloud'.";
80 public string ComparisonPageButton = "See comparison page";
81 public string YourPhotonServerLabel = "Your Photon Server";
82 public string AddressIPLabel = "Address/ip:";
83 public string PortLabel = "Port:";
84 public string LicensesLabel = "Licenses";
85 public string LicenseDownloadText = "Free License Download";
86 public string LicenseDownloadTooltip = "Get your free license for up to 100 concurrent players.";
87 public string TryPhotonAppLabel = "Running my own server is too much hassle..\nI want to give Photon's free app a try.";
88 public string GetCloudAppButton = "Get the free cloud app";
89 public string ConnectionTitle = "Connecting";
90 public string ConnectionInfo = "Connecting to the account service..";
91 public string ErrorTextTitle = "Error";
92 public string ServerSettingsMissingLabel = "Photon Unity Networking (PUN) is missing the 'ServerSettings' script. Re-import PUN to fix this.";
93 public string MoreThanOneLabel = "There are more than one ";
94 public string FilesInResourceFolderLabel = " files in 'Resources' folder. Check your project to keep only one. Using: ";
95 public string IncorrectRPCListTitle = "Warning: RPC-list becoming incompatible!";
96 public string IncorrectRPCListLabel = "Your project's RPC-list is full, so we can't add some RPCs just compiled.\n\nBy removing outdated RPCs, the list will be long enough but incompatible with older client builds!\n\nMake sure you change the game version where you use PhotonNetwork.ConnectUsingSettings().";
97 public string RemoveOutdatedRPCsLabel = "Remove outdated RPCs";
98 public string FullRPCListTitle = "Warning: RPC-list is full!";
99 public string FullRPCListLabel = "Your project's RPC-list is too long for PUN.\n\nYou can change PUN's source to use short-typed RPC index. Look for comments 'LIMITS RPC COUNT'\n\nAlternatively, remove some RPC methods (use more parameters per RPC maybe).\n\nAfter a RPC-list refresh, make sure you change the game version where you use PhotonNetwork.ConnectUsingSettings().";
100 public string SkipRPCListUpdateLabel = "Skip RPC-list update";
101 public string PUNNameReplaceTitle = "Warning: RPC-list Compatibility";
102 public string PUNNameReplaceLabel = "PUN replaces RPC names with numbers by using the RPC-list. All clients must use the same list for that.\n\nClearing it most likely makes your client incompatible with previous versions! Change your game version or make sure the RPC-list matches other clients.";
103 public string RPCListCleared = "Clear RPC-list";
104 public string ServerSettingsCleanedWarning = "Cleared the PhotonServerSettings.RpcList! This makes new builds incompatible with older ones. Better change game version in PhotonNetwork.ConnectUsingSettings().";
105 public string BestRegionLabel = "best";
106 }
107
108
109 [InitializeOnLoad]
110 public class PhotonEditor : EditorWindow
111 {
112 public static Text CurrentLang = new Text();
113
114 protected static AccountService.Origin RegisterOrigin = AccountService.Origin.Pun;
115
116 protected Vector2 scrollPos = Vector2.zero;
117
118 protected static string DocumentationLocation = "Assets/Photon Unity Networking/PhotonNetwork-Documentation.pdf";
119
120 protected static string UrlFreeLicense = "https://www.exitgames.com/en/OnPremise/Dashboard";
121
122 protected static string UrlDevNet = "http://doc.exitgames.com/en/pun/current/getting-started";
123
124 protected static string UrlForum = "http://forum.exitgames.com";
125
126 protected static string UrlCompare = "http://doc.exitgames.com/en/realtime/current/getting-started/onpremise-or-saas";
127
128 protected static string UrlHowToSetup = "http://doc.exitgames.com/en/onpremise/current/getting-started/photon-server-in-5min";
129
130 protected static string UrlAppIDExplained = "http://doc.exitgames.com/en/realtime/current/getting-started/obtain-your-app-id";
131
132 protected static string UrlAccountPage = "https://www.exitgames.com/Account/SignIn?email="; // opened in browser
133
134 protected static string UrlCloudDashboard = "https://cloud.exitgames.com/Dashboard?email=";
135
136
137 private enum GUIState
138 {
139 Uninitialized,
140
141 Main,
142
143 Setup
144 }
145
146 private enum PhotonSetupStates
147 {
148 RegisterForPhotonCloud,
149
150 EmailAlreadyRegistered,
151
152 SetupPhotonCloud,
153
154 SetupSelfHosted
155 }
156
157 private GUIState guiState = GUIState.Uninitialized;
158
159 private bool isSetupWizard = false;
160
161 bool open = false;
162
163 private PhotonSetupStates photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
164
165 private static double lastWarning = 0;
166
167 private static bool postCompileActionsDone;
168
169
170 private string photonAddress = "127.0.0.1"; // custom server
171
172 private int photonPort = 5055;
173
174 private ConnectionProtocol photonProtocol;
175
176
177 private string emailAddress = string.Empty;
178
179 private string cloudAppId = string.Empty;
180
181 private static bool dontCheckPunSetupField;
182
183 private static Texture2D WizardIcon;
184
185 protected static Type WindowType = typeof(PhotonEditor);
186
187 private static readonly string[] CloudServerRegionNames;
188 private static CloudRegionCode selectedRegion;
189 private bool helpRegion;
190
191 private static bool isPunPlus;
192 private static bool androidLibExists;
193 private static bool iphoneLibExists;
194
195 /// <summary>
196 /// Can be used to (temporarily) disable the checks for PUN Setup and scene PhotonViews.
197 /// This will prevent scene PhotonViews from being updated, so be careful.
198 /// When you re-set this value, checks are used again and scene PhotonViews get IDs as needed.
199 /// </summary>
200 protected static bool dontCheckPunSetup
201 {
202 get
203 {
204 return dontCheckPunSetupField;
205 }
206 set
207 {
208 if (dontCheckPunSetupField != value)
209 {
210 dontCheckPunSetupField = value;
211 }
212 }
213 }
214
215 static PhotonEditor()
216 {
217 EditorApplication.projectWindowChanged += EditorUpdate;
218 EditorApplication.hierarchyWindowChanged += EditorUpdate;
219 EditorApplication.playmodeStateChanged += PlaymodeStateChanged;
220 EditorApplication.update += OnUpdate;
221
222 WizardIcon = AssetDatabase.LoadAssetAtPath("Assets/Photon Unity Networking/photoncloud-icon.png", typeof(Texture2D)) as Texture2D;
223
224 // to be used in toolbar, the enum needs conversion to string[] being done here, once.
225 Array enumValues = Enum.GetValues(typeof(CloudRegionCode));
226 CloudServerRegionNames = new string[enumValues.Length];
227 for (int i = 0; i < CloudServerRegionNames.Length; i++)
228 {
229 CloudServerRegionNames[i] = enumValues.GetValue(i).ToString();
230 if (CloudServerRegionNames[i].Equals("none"))
231 {
232 CloudServerRegionNames[i] = PhotonEditor.CurrentLang.BestRegionLabel;
233 }
234 }
235
236 // detect optional packages
237 PhotonEditor.CheckPunPlus();
238
239 }
240
241 internal protected static bool CheckPunPlus()
242 {
243 androidLibExists = File.Exists("Assets/Plugins/Android/libPhotonSocketPlugin.so");
244 iphoneLibExists = File.Exists("Assets/Plugins/IPhone/libPhotonSocketPlugin.a");
245
246 isPunPlus = androidLibExists || iphoneLibExists;
247 return isPunPlus;
248 }
249
250 private static void ImportWin8Support()
251 {
252 if (EditorApplication.isCompiling || EditorApplication.isPlayingOrWillChangePlaymode)
253 {
254 return; // don't import while compiling
255 }
256
257 #if UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_5_1 || UNITY_5_2
258 const string win8Package = "Assets/Plugins/Photon3Unity3D-Win8.unitypackage";
259
260 bool win8LibsExist = File.Exists("Assets/Plugins/WP8/Photon3Unity3D.dll") && File.Exists("Assets/Plugins/Metro/Photon3Unity3D.dll");
261 if (!win8LibsExist && File.Exists(win8Package))
262 {
263 AssetDatabase.ImportPackage(win8Package, false);
264 }
265 #endif
266 }
267
268 [MenuItem("Window/Photon Unity Networking/Locate Settings Asset %#&p")]
269 protected static void Inspect()
270 {
271 EditorGUIUtility.PingObject(PhotonNetwork.PhotonServerSettings);
272 Selection.activeObject = PhotonNetwork.PhotonServerSettings;
273 }
274
275 [MenuItem("Window/Photon Unity Networking/PUN Wizard &p")]
276 protected static void Init()
277 {
278 PhotonEditor win = GetWindow(WindowType, false, CurrentLang.WindowTitle, true) as PhotonEditor;
279 win.InitPhotonSetupWindow();
280
281 win.isSetupWizard = false;
282 win.SwitchMenuState(GUIState.Main);
283 }
284
285 /// <summary>Creates an Editor window, showing the cloud-registration wizard for Photon (entry point to setup PUN).</summary>
286 protected static void ShowRegistrationWizard()
287 {
288 PhotonEditor win = GetWindow(WindowType, false, CurrentLang.WindowTitle, true) as PhotonEditor;
289 win.isSetupWizard = true;
290 win.InitPhotonSetupWindow();
291 }
292
293 /// <summary>Re-initializes the Photon Setup window and shows one of three states: register cloud, setup cloud, setup self-hosted.</summary>
294 protected void InitPhotonSetupWindow()
295 {
296 this.minSize = MinSize;
297
298 this.SwitchMenuState(GUIState.Setup);
299 this.ReApplySettingsToWindow();
300
301 switch (PhotonEditor.Current.HostType)
302 {
303 case ServerSettings.HostingOption.PhotonCloud:
304 case ServerSettings.HostingOption.BestRegion:
305 this.photonSetupState = PhotonSetupStates.SetupPhotonCloud;
306 break;
307 case ServerSettings.HostingOption.SelfHosted:
308 this.photonSetupState = PhotonSetupStates.SetupSelfHosted;
309 break;
310 case ServerSettings.HostingOption.NotSet:
311 default:
312 this.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
313 break;
314 }
315 }
316
317 // called 100 times / sec
318 private static void OnUpdate()
319 {
320 // after a compile, check RPCs to create a cache-list
321 if (!postCompileActionsDone && !EditorApplication.isCompiling && !EditorApplication.isPlayingOrWillChangePlaymode && PhotonEditor.Current != null)
322 {
323 #if UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_5_1 || UNITY_5_2
324 if (EditorApplication.isUpdating) return;
325 #endif
326
327 PhotonEditor.UpdateRpcList();
328 postCompileActionsDone = true; // on compile, this falls back to false (without actively doing anything)
329
330 #if UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_5_1 || UNITY_5_2
331 PhotonEditor.ImportWin8Support();
332 #endif
333 }
334 }
335
336 // called in editor, opens wizard for initial setup, keeps scene PhotonViews up to date and closes connections when compiling (to avoid issues)
337 private static void EditorUpdate()
338 {
339 if (dontCheckPunSetup || PhotonEditor.Current == null)
340 {
341 return;
342 }
343
344 // serverSetting is null when the file gets deleted. otherwise, the wizard should only run once and only if hosting option is not (yet) set
345 if (!PhotonEditor.Current.DisableAutoOpenWizard && PhotonEditor.Current.HostType == ServerSettings.HostingOption.NotSet)
346 {
347 ShowRegistrationWizard();
348 }
349
350 // Workaround for TCP crash. Plus this surpresses any other recompile errors.
351 if (EditorApplication.isCompiling)
352 {
353 if (PhotonNetwork.connected)
354 {
355 if (lastWarning > EditorApplication.timeSinceStartup - 3)
356 {
357 // Prevent error spam
358 Debug.LogWarning(CurrentLang.WarningPhotonDisconnect);
359 lastWarning = EditorApplication.timeSinceStartup;
360 }
361
362 PhotonNetwork.Disconnect();
363 }
364 }
365 }
366
367 // called in editor on change of play-mode (used to show a message popup that connection settings are incomplete)
368 private static void PlaymodeStateChanged()
369 {
370 if (dontCheckPunSetup || EditorApplication.isPlaying || !EditorApplication.isPlayingOrWillChangePlaymode)
371 {
372 return;
373 }
374
375 if (PhotonEditor.Current.HostType == ServerSettings.HostingOption.NotSet)
376 {
377 EditorUtility.DisplayDialog(CurrentLang.SetupWizardWarningTitle, CurrentLang.SetupWizardWarningMessage, CurrentLang.OkButton);
378 }
379 }
380
381 private void SwitchMenuState(GUIState newState)
382 {
383 this.guiState = newState;
384 if (this.isSetupWizard && newState != GUIState.Setup)
385 {
386 this.Close();
387 }
388 }
389
390 protected virtual void OnGUI()
391 {
392 PhotonSetupStates oldGuiState = this.photonSetupState; // used to fix an annoying Editor input field issue: wont refresh until focus is changed.
393
394 GUI.SetNextControlName("");
395 this.scrollPos = GUILayout.BeginScrollView(this.scrollPos);
396
397 if (this.guiState == GUIState.Uninitialized)
398 {
399 this.ReApplySettingsToWindow();
400 this.guiState = (PhotonEditor.Current.HostType == ServerSettings.HostingOption.NotSet) ? GUIState.Setup : GUIState.Main;
401 }
402
403 if (this.guiState == GUIState.Main)
404 {
405 this.OnGuiMainWizard();
406 }
407 else
408 {
409 this.OnGuiRegisterCloudApp();
410 }
411
412 GUILayout.EndScrollView();
413
414 if (oldGuiState != this.photonSetupState)
415 {
416 GUI.FocusControl("");
417 }
418 }
419
420 protected virtual void OnGuiRegisterCloudApp()
421 {
422 GUI.skin.label.wordWrap = true;
423 if (!this.isSetupWizard)
424 {
425 GUILayout.BeginHorizontal();
426 GUILayout.FlexibleSpace();
427 if (GUILayout.Button(CurrentLang.MainMenuButton, GUILayout.ExpandWidth(false)))
428 {
429 this.SwitchMenuState(GUIState.Main);
430 }
431
432 GUILayout.EndHorizontal();
433
434 GUILayout.Space(15);
435 }
436
437 if (this.photonSetupState == PhotonSetupStates.RegisterForPhotonCloud)
438 {
439 GUI.skin.label.fontStyle = FontStyle.Bold;
440 GUILayout.Label(CurrentLang.ConnectButton);
441 EditorGUILayout.Separator();
442 GUI.skin.label.fontStyle = FontStyle.Normal;
443
444 GUILayout.Label(CurrentLang.UsePhotonLabel);
445 EditorGUILayout.Separator();
446 this.emailAddress = EditorGUILayout.TextField(CurrentLang.EmailLabel, this.emailAddress);
447
448 if (GUILayout.Button(CurrentLang.SendButton))
449 {
450 GUIUtility.keyboardControl = 0;
451 this.RegisterWithEmail(this.emailAddress);
452 }
453
454 GUILayout.Space(20);
455
456
457 GUILayout.Label(CurrentLang.SignedUpAlreadyLabel);
458 if (GUILayout.Button(CurrentLang.SetupButton))
459 {
460 this.photonSetupState = PhotonSetupStates.SetupPhotonCloud;
461 }
462 EditorGUILayout.Separator();
463
464
465 GUILayout.Label(CurrentLang.RegisterByWebsiteLabel);
466 if (GUILayout.Button(CurrentLang.AccountWebsiteButton))
467 {
468 EditorUtility.OpenWithDefaultApp(UrlAccountPage + Uri.EscapeUriString(this.emailAddress));
469 }
470
471 EditorGUILayout.Separator();
472
473 GUILayout.Label(CurrentLang.SelfHostLabel);
474
475 if (GUILayout.Button(CurrentLang.SelfHostSettingsButton))
476 {
477 this.photonSetupState = PhotonSetupStates.SetupSelfHosted;
478 }
479
480 GUILayout.FlexibleSpace();
481
482
483 if (!InternalEditorUtility.HasAdvancedLicenseOnBuildTarget(BuildTarget.Android) || !InternalEditorUtility.HasAdvancedLicenseOnBuildTarget(BuildTarget.iOS))
484 {
485 GUILayout.Label(CurrentLang.MobileExportNoteLabel);
486 }
487 EditorGUILayout.Separator();
488 }
489 else if (this.photonSetupState == PhotonSetupStates.EmailAlreadyRegistered)
490 {
491 GUI.skin.label.fontStyle = FontStyle.Bold;
492 GUILayout.Label(CurrentLang.OopsLabel);
493 GUI.skin.label.fontStyle = FontStyle.Normal;
494
495 GUILayout.Label(CurrentLang.EmailInUseLabel);
496
497 if (GUILayout.Button(CurrentLang.SeeMyAccountPageButton))
498 {
499 EditorUtility.OpenWithDefaultApp(UrlCloudDashboard + Uri.EscapeUriString(this.emailAddress));
500 }
501
502 EditorGUILayout.Separator();
503
504 GUILayout.Label(CurrentLang.KnownAppIdLabel);
505 GUILayout.BeginHorizontal();
506 if (GUILayout.Button(CurrentLang.CancelButton))
507 {
508 this.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
509 }
510
511 if (GUILayout.Button(CurrentLang.SetupButton))
512 {
513 this.photonSetupState = PhotonSetupStates.SetupPhotonCloud;
514 }
515
516 GUILayout.EndHorizontal();
517 }
518 else if (this.photonSetupState == PhotonSetupStates.SetupPhotonCloud)
519 {
520 // cloud setup
521 GUI.skin.label.fontStyle = FontStyle.Bold;
522 GUILayout.Label(CurrentLang.PhotonCloudConnect);
523 GUI.skin.label.fontStyle = FontStyle.Normal;
524
525 EditorGUILayout.Separator();
526 this.OnGuiSetupCloudAppId();
527 this.OnGuiCompareAndHelpOptions();
528 }
529 else if (this.photonSetupState == PhotonSetupStates.SetupSelfHosted)
530 {
531 // self-hosting setup
532 GUI.skin.label.fontStyle = FontStyle.Bold;
533 GUILayout.Label(CurrentLang.SetupOwnHostLabel);
534 GUI.skin.label.fontStyle = FontStyle.Normal;
535
536 EditorGUILayout.Separator();
537
538 this.OnGuiSetupSelfhosting();
539 this.OnGuiCompareAndHelpOptions();
540 }
541 }
542
543 protected virtual void OnGuiMainWizard()
544 {
545 GUILayout.BeginHorizontal();
546 GUILayout.FlexibleSpace();
547 GUILayout.Label(WizardIcon);
548 GUILayout.FlexibleSpace();
549 GUILayout.EndHorizontal();
550
551 EditorGUILayout.Separator();
552
553 GUILayout.Label(CurrentLang.PUNWizardLabel, EditorStyles.boldLabel);
554 if (isPunPlus)
555 {
556 GUILayout.Label(CurrentLang.MobilePunPlusExportNoteLabel);
557 }
558 else if (!InternalEditorUtility.HasAdvancedLicenseOnBuildTarget(BuildTarget.Android) || !InternalEditorUtility.HasAdvancedLicenseOnBuildTarget(BuildTarget.iOS))
559 {
560 GUILayout.Label(CurrentLang.MobileExportNoteLabel);
561 }
562 EditorGUILayout.Separator();
563
564
565 // settings button
566 GUILayout.BeginHorizontal();
567 GUILayout.Label(CurrentLang.SettingsButton, EditorStyles.boldLabel, GUILayout.Width(100));
568 if (GUILayout.Button(new GUIContent(CurrentLang.SetupButton, CurrentLang.SetupServerCloudLabel)))
569 {
570 this.InitPhotonSetupWindow();
571 }
572
573 GUILayout.EndHorizontal();
574 EditorGUILayout.Separator();
575
576
577 // find / select settings asset
578 GUILayout.BeginHorizontal();
579 GUILayout.Label(CurrentLang.SettingsFileLabel, EditorStyles.boldLabel, GUILayout.Width(100));
580 if (GUILayout.Button(new GUIContent(CurrentLang.LocateSettingsButton, CurrentLang.SettingsHighlightLabel)))
581 {
582 EditorGUIUtility.PingObject(PhotonEditor.Current);
583 }
584
585 GUILayout.EndHorizontal();
586
587
588 GUILayout.FlexibleSpace();
589
590 // converter
591 GUILayout.BeginHorizontal();
592 GUILayout.Label(CurrentLang.ConverterLabel, EditorStyles.boldLabel, GUILayout.Width(100));
593 if (GUILayout.Button(new GUIContent(CurrentLang.StartButton, CurrentLang.UNtoPUNLabel)))
594 {
595 PhotonConverter.RunConversion();
596 }
597
598 GUILayout.EndHorizontal();
599 EditorGUILayout.Separator();
600
601
602 // documentation
603 GUILayout.BeginHorizontal();
604 GUILayout.Label(CurrentLang.DocumentationLabel, EditorStyles.boldLabel, GUILayout.Width(100));
605 GUILayout.BeginVertical();
606 if (GUILayout.Button(new GUIContent(CurrentLang.OpenPDFText, CurrentLang.OpenPDFTooltip)))
607 {
608 EditorUtility.OpenWithDefaultApp(DocumentationLocation);
609 }
610
611 if (GUILayout.Button(new GUIContent(CurrentLang.OpenDevNetText, CurrentLang.OpenDevNetTooltip)))
612 {
613 EditorUtility.OpenWithDefaultApp(UrlDevNet);
614 }
615
616 if (GUILayout.Button(new GUIContent(CurrentLang.OpenCloudDashboardText, CurrentLang.OpenCloudDashboardTooltip)))
617 {
618 EditorUtility.OpenWithDefaultApp(UrlCloudDashboard + Uri.EscapeUriString(this.emailAddress));
619 }
620
621 if (GUILayout.Button(new GUIContent(CurrentLang.OpenForumText, CurrentLang.OpenForumTooltip)))
622 {
623 EditorUtility.OpenWithDefaultApp(UrlForum);
624 }
625
626 GUILayout.EndVertical();
627 GUILayout.EndHorizontal();
628 }
629
630 protected virtual void OnGuiCompareAndHelpOptions()
631 {
632 GUILayout.FlexibleSpace();
633
634 GUILayout.Label(CurrentLang.QuestionsLabel);
635 if (GUILayout.Button(CurrentLang.SeeForumButton))
636 {
637 Application.OpenURL(UrlForum);
638 }
639
640 if (photonSetupState != PhotonSetupStates.SetupSelfHosted)
641 {
642 if (GUILayout.Button(CurrentLang.OpenDashboardButton))
643 {
644 EditorUtility.OpenWithDefaultApp(UrlCloudDashboard + Uri.EscapeUriString(this.emailAddress));
645 }
646 }
647 }
648
649 protected virtual void OnGuiSetupCloudAppId()
650 {
651 GUILayout.Label(CurrentLang.AppIdLabel);
652
653 GUILayout.BeginHorizontal();
654 this.cloudAppId = EditorGUILayout.TextField(this.cloudAppId);
655
656 open = GUILayout.Toggle(open, PhotonGUI.HelpIcon, GUIStyle.none, GUILayout.ExpandWidth(false));
657
658 GUILayout.EndHorizontal();
659
660 if (open) GUILayout.Label(CurrentLang.AppIdInfoLabel);
661
662
663
664 EditorGUILayout.Separator();
665
666 GUILayout.Label(CurrentLang.CloudRegionLabel);
667
668 GUILayout.BeginHorizontal();
669 int toolbarValue = GUILayout.Toolbar((int)selectedRegion, CloudServerRegionNames); // the enum CloudRegionCode is converted into a string[] in init (toolbar can't use enum)
670 helpRegion = GUILayout.Toggle( helpRegion, PhotonGUI.HelpIcon, GUIStyle.none, GUILayout.ExpandWidth( false ) );
671 GUILayout.EndHorizontal();
672
673
674 if (helpRegion) GUILayout.Label(CurrentLang.RegionalServersInfo);
675 PhotonEditor.selectedRegion = (CloudRegionCode)toolbarValue;
676
677 EditorGUILayout.Separator();
678
679 GUILayout.BeginHorizontal();
680 if (GUILayout.Button(CurrentLang.CancelButton))
681 {
682 GUIUtility.keyboardControl = 0;
683 this.ReApplySettingsToWindow();
684 }
685
686
687
688 if (GUILayout.Button(CurrentLang.SaveButton))
689 {
690 GUIUtility.keyboardControl = 0;
691 this.cloudAppId = this.cloudAppId.Trim();
692 PhotonEditor.Current.UseCloud(this.cloudAppId);
693
694 PhotonEditor.Current.PreferredRegion = PhotonEditor.selectedRegion;
695 PhotonEditor.Current.HostType = (PhotonEditor.Current.PreferredRegion == CloudRegionCode.none)
696 ? ServerSettings.HostingOption.BestRegion
697 : ServerSettings.HostingOption.PhotonCloud;
698 PhotonEditor.Save();
699
700 Inspect();
701 EditorUtility.DisplayDialog(CurrentLang.SettingsSavedTitle, CurrentLang.SettingsSavedMessage, CurrentLang.OkButton);
702 }
703
704 GUILayout.EndHorizontal();
705
706
707
708 GUILayout.Space(20);
709
710 GUILayout.Label(CurrentLang.SetupOwnServerLabel);
711
712 if (GUILayout.Button(CurrentLang.SelfHostSettingsButton))
713 {
714 //this.photonAddress = ServerSettings.DefaultServerAddress;
715 //this.photonPort = ServerSettings.DefaultMasterPort;
716 this.photonSetupState = PhotonSetupStates.SetupSelfHosted;
717 }
718
719 EditorGUILayout.Separator();
720 GUILayout.Label(CurrentLang.OwnHostCloudCompareLabel);
721 if (GUILayout.Button(CurrentLang.ComparisonPageButton))
722 {
723 Application.OpenURL(UrlCompare);
724 }
725 }
726
727 protected virtual void OnGuiSetupSelfhosting()
728 {
729 GUILayout.Label(CurrentLang.YourPhotonServerLabel);
730
731 this.photonAddress = EditorGUILayout.TextField(CurrentLang.AddressIPLabel, this.photonAddress);
732 this.photonPort = EditorGUILayout.IntField(CurrentLang.PortLabel, this.photonPort);
733 this.photonProtocol = (ConnectionProtocol)EditorGUILayout.EnumPopup("Protocol", this.photonProtocol);
734 EditorGUILayout.Separator();
735
736 GUILayout.BeginHorizontal();
737 if (GUILayout.Button(CurrentLang.CancelButton))
738 {
739 GUIUtility.keyboardControl = 0;
740 this.ReApplySettingsToWindow();
741 }
742
743 if (GUILayout.Button(CurrentLang.SaveButton))
744 {
745 GUIUtility.keyboardControl = 0;
746
747 PhotonEditor.Current.UseMyServer(this.photonAddress, this.photonPort, null);
748 PhotonEditor.Current.Protocol = this.photonProtocol;
749 PhotonEditor.Save();
750
751 Inspect();
752 EditorUtility.DisplayDialog(CurrentLang.SettingsSavedTitle, CurrentLang.SettingsSavedMessage, CurrentLang.OkButton);
753 }
754
755 GUILayout.EndHorizontal();
756
757
758 GUILayout.Space(20);
759
760
761 // license
762 GUILayout.BeginHorizontal();
763 GUILayout.Label(CurrentLang.LicensesLabel, EditorStyles.boldLabel, GUILayout.Width(100));
764
765 if (GUILayout.Button(new GUIContent(CurrentLang.LicenseDownloadText, CurrentLang.LicenseDownloadTooltip)))
766 {
767 EditorUtility.OpenWithDefaultApp(UrlFreeLicense);
768 }
769
770 GUILayout.EndHorizontal();
771
772
773 GUILayout.Space(20);
774
775
776 GUILayout.Label(CurrentLang.TryPhotonAppLabel);
777
778 if (GUILayout.Button(CurrentLang.GetCloudAppButton))
779 {
780 this.cloudAppId = string.Empty;
781 this.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
782 }
783
784 EditorGUILayout.Separator();
785 GUILayout.Label(CurrentLang.OwnHostCloudCompareLabel);
786 if (GUILayout.Button(CurrentLang.ComparisonPageButton))
787 {
788 Application.OpenURL(UrlCompare);
789 }
790 }
791
792 protected virtual void RegisterWithEmail(string email)
793 {
794 EditorUtility.DisplayProgressBar(CurrentLang.ConnectionTitle, CurrentLang.ConnectionInfo, 0.5f);
795 var client = new AccountService();
796 client.RegisterByEmail(email, RegisterOrigin); // this is the synchronous variant using the static RegisterOrigin. "result" is in the client
797
798 EditorUtility.ClearProgressBar();
799 if (client.ReturnCode == 0)
800 {
801 PhotonEditor.Current.UseCloud(client.AppId, 0);
802 PhotonEditor.Save();
803 this.ReApplySettingsToWindow();
804 this.photonSetupState = PhotonSetupStates.SetupPhotonCloud;
805 }
806 else
807 {
808 if (client.Message.Contains(CurrentLang.EmailInUseLabel))
809 {
810 this.photonSetupState = PhotonSetupStates.EmailAlreadyRegistered;
811 }
812 else
813 {
814 EditorUtility.DisplayDialog(CurrentLang.ErrorTextTitle, client.Message, CurrentLang.OkButton);
815 // Debug.Log(client.Exception);
816 this.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
817 }
818 }
819 }
820
821 #region SettingsFileHandling
822
823 private static ServerSettings currentSettings;
824 private Vector2 MinSize = new Vector2(350, 400);
825
826 public static ServerSettings Current
827 {
828 get
829 {
830 if (currentSettings == null)
831 {
832 // find out if ServerSettings can be instantiated (existing script check)
833 ScriptableObject serverSettingTest = CreateInstance("ServerSettings");
834 if (serverSettingTest == null)
835 {
836 Debug.LogError(CurrentLang.ServerSettingsMissingLabel);
837 return null;
838 }
839 DestroyImmediate(serverSettingTest);
840
841 // try to load settings from file
842 ReLoadCurrentSettings();
843
844 // if still not loaded, create one
845 if (currentSettings == null)
846 {
847 string settingsPath = Path.GetDirectoryName(PhotonNetwork.serverSettingsAssetPath);
848 if (!Directory.Exists(settingsPath))
849 {
850 Directory.CreateDirectory(settingsPath);
851 AssetDatabase.ImportAsset(settingsPath);
852 }
853
854 currentSettings = (ServerSettings)ScriptableObject.CreateInstance("ServerSettings");
855 if (currentSettings != null)
856 {
857 AssetDatabase.CreateAsset(currentSettings, PhotonNetwork.serverSettingsAssetPath);
858 }
859 else
860 {
861 Debug.LogError(CurrentLang.ServerSettingsMissingLabel);
862 }
863 }
864
865 // settings were loaded or created. set this editor's initial selected region now (will be changed in GUI)
866 if (currentSettings != null)
867 {
868 selectedRegion = currentSettings.PreferredRegion;
869 }
870 }
871
872 return currentSettings;
873 }
874
875 protected set
876 {
877 currentSettings = value;
878 }
879 }
880
881 public static void Save()
882 {
883 EditorUtility.SetDirty(PhotonEditor.Current);
884 }
885
886 public static void ReLoadCurrentSettings()
887 {
888 // this now warns developers if there are more than one settings files in resources folders. first will be used.
889 UnityEngine.Object[] settingFiles = Resources.LoadAll(PhotonNetwork.serverSettingsAssetFile, typeof(ServerSettings));
890 if (settingFiles != null && settingFiles.Length > 0)
891 {
892 PhotonEditor.Current = (ServerSettings)settingFiles[0];
893
894 if (settingFiles.Length > 1)
895 {
896 Debug.LogWarning(CurrentLang.MoreThanOneLabel + PhotonNetwork.serverSettingsAssetFile + CurrentLang.FilesInResourceFolderLabel + AssetDatabase.GetAssetPath(PhotonEditor.Current));
897 }
898 }
899 }
900
901 protected void ReApplySettingsToWindow()
902 {
903 this.cloudAppId = string.IsNullOrEmpty(PhotonEditor.Current.AppID) ? string.Empty : PhotonEditor.Current.AppID;
904 this.photonAddress = string.IsNullOrEmpty(PhotonEditor.Current.ServerAddress) ? string.Empty : PhotonEditor.Current.ServerAddress;
905 this.photonPort = PhotonEditor.Current.ServerPort;
906 this.photonProtocol = PhotonEditor.Current.Protocol;
907 }
908
909 public static void UpdateRpcList()
910 {
911 List<string> additionalRpcs = new List<string>();
912 HashSet<string> currentRpcs = new HashSet<string>();
913
914 var types = GetAllSubTypesInScripts(typeof(MonoBehaviour));
915
916 foreach (var mono in types)
917 {
918 MethodInfo[] methods = mono.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
919
920 foreach (MethodInfo method in methods)
921 {
922 if (method.IsDefined(typeof(UnityEngine.RPC), false))
923 {
924 currentRpcs.Add(method.Name);
925
926 if (!additionalRpcs.Contains(method.Name) && !PhotonEditor.Current.RpcList.Contains(method.Name))
927 {
928 additionalRpcs.Add(method.Name);
929 }
930 }
931 }
932 }
933
934 if (additionalRpcs.Count > 0)
935 {
936 // LIMITS RPC COUNT
937 if (additionalRpcs.Count + PhotonEditor.Current.RpcList.Count >= byte.MaxValue)
938 {
939 if (currentRpcs.Count <= byte.MaxValue)
940 {
941 bool clearList = EditorUtility.DisplayDialog(CurrentLang.IncorrectRPCListTitle, CurrentLang.IncorrectRPCListLabel, CurrentLang.RemoveOutdatedRPCsLabel, CurrentLang.CancelButton);
942 if (clearList)
943 {
944 PhotonEditor.Current.RpcList.Clear();
945 PhotonEditor.Current.RpcList.AddRange(currentRpcs);
946 }
947 else
948 {
949 return;
950 }
951 }
952 else
953 {
954 EditorUtility.DisplayDialog(CurrentLang.FullRPCListTitle, CurrentLang.FullRPCListLabel, CurrentLang.SkipRPCListUpdateLabel);
955 return;
956 }
957 }
958
959 additionalRpcs.Sort();
960 PhotonEditor.Current.RpcList.AddRange(additionalRpcs);
961 EditorUtility.SetDirty(PhotonEditor.Current);
962 }
963 }
964
965 public static void ClearRpcList()
966 {
967 bool clearList = EditorUtility.DisplayDialog(CurrentLang.PUNNameReplaceTitle, CurrentLang.PUNNameReplaceLabel, CurrentLang.RPCListCleared, CurrentLang.CancelButton);
968 if (clearList)
969 {
970 PhotonEditor.Current.RpcList.Clear();
971 Debug.LogWarning(CurrentLang.ServerSettingsCleanedWarning);
972 }
973 }
974
975 public static System.Type[] GetAllSubTypesInScripts(System.Type aBaseClass)
976 {
977 var result = new System.Collections.Generic.List<System.Type>();
978 System.Reflection.Assembly[] AS = System.AppDomain.CurrentDomain.GetAssemblies();
979 foreach (var A in AS)
980 {
981 // this skips all but the Unity-scripted assemblies for RPC-list creation. You could remove this to search all assemblies in project
982 if (!A.FullName.StartsWith("Assembly-"))
983 {
984 // Debug.Log("Skipping Assembly: " + A);
985 continue;
986 }
987
988 //Debug.Log("Assembly: " + A.FullName);
989 System.Type[] types = A.GetTypes();
990 foreach (var T in types)
991 {
992 if (T.IsSubclassOf(aBaseClass))
993 result.Add(T);
994 }
995 }
996 return result.ToArray();
997 }
998
999 #endregion
1000 }
----------------------------------------------------------------------------
PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH
MenuItems and in-Editor scripts for PhotonNetwork.
----------------------------------------------------------------------------
protected static string UrlFreeLicense = "https:www.exitgames.comenOnPremiseDashboard";
protected static string UrlDevNet = "http:doc.exitgames.comenpuncurrentgetting-started";
protected static string UrlForum = "http:forum.exitgames.com";
protected static string UrlCompare = "http:doc.exitgames.comenrealtimecurrentgetting-startedonpremise-or-saas";
protected static string UrlHowToSetup = "http:doc.exitgames.comenonpremisecurrentgetting-startedphoton-server-in-5min";
protected static string UrlAppIDExplained = "http:doc.exitgames.comenrealtimecurrentgetting-startedobtain-your-app-id";
protected static string UrlAccountPage = "https:www.exitgames.comAccountSignIn?email="; opened in browser
protected static string UrlCloudDashboard = "https:cloud.exitgames.comDashboard?email=";
private string photonAddress = "127.0.0.1"; custom server
Can be used to (temporarily) disable the checks for PUN Setup and scene PhotonViews.
This will prevent scene PhotonViews from being updated, so be careful.
When you re-set this value, checks are used again and scene PhotonViews get IDs as needed.
to be used in toolbar, the enum needs conversion to string[] being done here, once.
detect optional packages
return; don't import while compiling
called 100 times sec
after a compile, check RPCs to create a cache-list
postCompileActionsDone = true; on compile, this falls back to false (without actively doing anything)
called in editor, opens wizard for initial setup, keeps scene PhotonViews up to date and closes connections when compiling (to avoid issues)
serverSetting is null when the file gets deleted. otherwise, the wizard should only run once and only if hosting option is not (yet) set
Workaround for TCP crash. Plus this surpresses any other recompile errors.
Prevent error spam
called in editor on change of play-mode (used to show a message popup that connection settings are incomplete)
PhotonSetupStates oldGuiState = this.photonSetupState; used to fix an annoying Editor input field issue: wont refresh until focus is changed.
cloud setup
self-hosting setup
settings button
find select settings asset
converter
documentation
int toolbarValue = GUILayout.Toolbar((int)selectedRegion, CloudServerRegionNames); the enum CloudRegionCode is converted into a string[] in init (toolbar can't use enum)
this.photonAddress = ServerSettings.DefaultServerAddress;
this.photonPort = ServerSettings.DefaultMasterPort;
license
client.RegisterByEmail(email, RegisterOrigin); this is the synchronous variant using the static RegisterOrigin. "result" is in the client
Debug.Log(client.Exception);
find out if ServerSettings can be instantiated (existing script check)
try to load settings from file
if still not loaded, create one
settings were loaded or created. set this editor's initial selected region now (will be changed in GUI)
this now warns developers if there are more than one settings files in resources folders. first will be used.
LIMITS RPC COUNT
this skips all but the Unity-scripted assemblies for RPC-list creation. You could remove this to search all assemblies in project
Debug.Log("Skipping Assembly: " + A);
Debug.Log("Assembly: " + A.FullName);